// 方案一：
// xx1

// 方案二：
// [xx1, xx2]

// 方案三：
// {
//   // 当只有一个元素时，是否构造为数组
//   isArray: true,
//   config: [{
//     // 必要
//     inputField: 'ii1',
//     inputDone: async (val,values)=>{

//     },
//     outputField: 'oo1',
//     outputDone: async (val,values)=>{

//     }
//   },{
//     // 必要
//     inputField: 'ii2',
//     inputDone: async (val,values)=>{

//     },
//     outputField: 'oo2',
//     outputDone: async (val,values)=>{

//     }
//   }]
// }
import { isUndef } from './index.js';
// 每个area会实例化唯一的nameManger实例
class NameManger {
	constructor(area, { initialValues, staticValues, ...config } = {}) {
		this.area = area;
		this.config = config;
		area.nameManger = this;
		// 记录新构造的键名和配置的映射
		this.fieldsSet = new Set();
		this.fieldsMap = new Map();
		this.staticValues = { ...staticValues };
		this.initialValues = { ...initialValues };
		// 在vue中，values是响应式数据，可以通过它调整表单回显，或实时获取数据
		this.values = area.hook.hookInitValues(this);
	}
	// 解析name完善数据
	input(name, { defaultValue } = {}) {
		const { fieldsMap, fieldsSet, values, area } = this;
		// 查找历史记录，以判定是否为重复执行name解析
		if (name) {
			if (typeof name === 'object') {
				// 包含数组和对象类型，此类name需要特殊解析处理
				if (fieldsMap.has(name)) return fieldsMap.get(name);
			} else if (fieldsSet.has(name)) return name;
		} else return;
		// ===============================================================
		let inputField, inputValue;
		if (Array.isArray(name)) {
			// 元素均为字符串类型，将数据组装成为数组
			inputField = name.join('__');
			inputValue = name.map(n => values[n]);
			fieldsMap.set(name, inputField);
		} else if (typeof name === 'object') {
			const { config } = name;
			if (!config) throw new Error('name为配置对象时，需定义config属性');
			inputValue = [];
			const done = items => {
				const keys = [];
				items = Array.isArray(items) ? items : [items];
				items.forEach(item => {
					const { inputField, inputDone } = item;
					let value = values[inputField];
					if (typeof inputDone === 'function') {
						// 浅拷贝防止数据污染，允许返回任意类型的数据，如对象等
						value = inputDone(value, { ...values });
					}
					keys.push(inputField);
					inputValue.push(value);
				});
				return keys.join('__');
			}
			inputField = done(config);
			// config为数组类型，则结果值数据类型保持一致
			// config非数组类型，则取出第一个元素作为结果值
			if (!Array.isArray(config)) inputValue = inputValue[0];
			fieldsMap.set(name, inputField);
		} else {
			// name为数字或字符串类型
			fieldsSet.add(inputField = name);
			inputValue = values[name];
		}
		const val = inputValue === undefined ? defaultValue : inputValue;
		const { ctx, hook } = area;
		hook.hookNameMangerInput(values, inputField, val, ctx);
		return inputField;
	}
	// values解析后，与staticValues合并后返回
	async output({ ...values } = this.values) {
		for (let [name, field] of this.fieldsMap) {
			const value = values[field];
			// 清除零时的冗余字段
			delete values[field];
			if (Array.isArray(name)) {
				if (isUndef(value)) {
					// 未定义，不做处理
				} else {
					// 元素均为字符串类型，直接还原即可
					name.forEach((n, k) => values[n] = value[k]);
				}
			} else {
				if (!name.config) throw new Error('name为配置对象时，需定义config属性');
				const done = async (v, k) => {
					const { inputField, outputField, outputDone } = v;
					let outputValue = value;
					if (isUndef(value)) {
						// 未定义，不做处理
					} else {
						outputValue = typeof k === 'number' ? value[k] : value;
					}
					if (typeof outputDone === 'function') {
						outputValue = await outputDone(outputValue, values);
					}
					// 未定义输出字段，则与输入字段保持一致
					values[outputField || inputField] = outputValue;
				};
				if (Array.isArray(name.config)) {
					await Promise.all(name.config.map(done));
				} else {
					await done(name.config);
				}
			}
		}
		return { ...this.staticValues, ...values };
	}
};
export default NameManger;